// this file contains game specific data and algorithms
// SINGLETON

#include <assert.h>

#include "game.h"
#include "statectrl.h"

#include <windows.h>
#include <math.h>
#include <stdlib.h>

#include "level.h"
#include "tools.h"
#include "physics.h"
#include "character.h"
#include "camera.h"
#include "defines.h"
#include "hunter.h"
#include "audio.h"
#include "io.h"
#include "ai.h"
#include "renderer.h"
#include "circle.h"
#include "frame.h"
#include "platform.h"
#include "slope.h"
#include "animation.h"
#include "zomby.h"
#include "source.h"
#include "fx.h"
#include "rect.h"
#include "point2.h"
#include "globals.h"
#include "input.h"
#include "projectile.h"
#include "globals.h"
#include "kolobok.h"
#include "cloud.h"
#include "respawn.h"
#include "bird.h"
#include "object.h"

#define _OPTIMIZE_collideRectToCircles
#define _OPTIMIZE_collideRectToSlopes
#define _OPTIMIZE_collideRectToFloors
#define _OPTIMIZE_collideRectToPlatforms
#define _OPTIMIZE_standsRectAtLevel

unsigned int g_ctr1 =0, g_ctr2 =0;

Game* Game::_instance = 0;

Game::Game(){
	bool trilinear =0;

	memset(keys, 0, 256);
	key_up =0;
	key_down =0;
	key_left =0;
	key_right =0;
	key_attack =0;
	key_special =0;
	sound =0;
	scores =0;
	cycle_time =0;
	jump_ready =true;

	_stand_prediction =PLATFORMS;

	_tan_133 =1.33*tan(30/57.29577957795135);
};

Game* Game::Instance(){

	if (_instance == 0){
	
		_instance = new Game;
	}
	return _instance;
}

// collide rectangle 'rect', moving by 'V', to all the circles in the 'level'
// return 'true' if there is a collision, n-normal to the point of collision 't_min' -its t
bool Game::collideRectToCircles(Level* level, Rect* rect, Point2* position, Point2* V, Point2* n, float* t_min, Object** object){

	assert(level);
	assert(rect);
	assert(position);

	float t_tmp;
	bool res;

	// initialization
	list<Circle*>::iterator iter;
	Point2 pLoLo, pHiLo, pLoHi, pHiHi;
	Physics* ph =Physics::Instance();
	Point2* p_tmp =NULL;
	res =false;
	
	/// for all the points of the 'rect' send rays to the circles
	pLoLo.x =rect->xLo +position->x;
	pLoLo.y =rect->yLo +position->y;	
	pHiLo.x =rect->xHi +position->x;
	pHiLo.y =rect->yLo +position->y;

	pLoHi.x =rect->xLo +position->x;
	pLoHi.y =rect->yHi +position->y;
	pHiHi.x =rect->xHi +position->x;
	pHiHi.y =rect->yHi +position->y;
	
	#ifdef _OPTIMIZE_collideRectToCircles
	Rect rect_tmp;
	Rect rect_tmp2;
	rect_tmp =*rect;
	addVectToRect(&rect_tmp, position);
	if(V->x>0)
		rect_tmp.xHi +=V->x;
	else
		rect_tmp.xLo +=V->x;
	if(V->y>0)
		rect_tmp.yHi +=V->y;
	else
		rect_tmp.yLo +=V->y;
	#endif

	float radius_ph;
	Point2* cposition;
	for(iter = level->circles.begin(); iter != level->circles.end(); iter++)
	{
		cposition =(*iter)->position;
		radius_ph = (*iter)->radius_ph;

		// check if expanded rect intersects with circles' rectangular boundaries 
		#ifdef _OPTIMIZE_collideRectToCircles
		rect_tmp2.xHi =cposition->x +radius_ph;
		rect_tmp2.xLo =cposition->x -radius_ph;
		rect_tmp2.yHi =cposition->y +radius_ph;
		rect_tmp2.yLo =cposition->y -radius_ph;
		if(!ph->collide_Rect_Rect_S(&rect_tmp, &rect_tmp2)){ 
			continue;
		}
		#endif

		#ifdef _OPTIMIZE_collideRectToCircles
		if(V->x<0 || V->y<0)
		#endif
		// check if any of the four points penetrate the circle
		if(ph->rayToCircle(cposition, radius_ph, &pLoLo, V, &t_tmp)){

//			if(t_tmp>0 && t_tmp<1){	//?
				if(!res || t_tmp<*t_min){

					p_tmp =&pLoLo;
					*t_min =t_tmp;
					*object =*iter;
					res =true;
				}
//			}
		}

		#ifdef _OPTIMIZE_collideRectToCircles
		if(V->x>0 || V->y<0)
		#endif
		if(ph->rayToCircle(cposition, radius_ph, &pHiLo, V, &t_tmp)){

//			if(t_tmp>0 && t_tmp<1){	//?

				if(!res || t_tmp<*t_min){

					p_tmp =&pHiLo;
					*t_min =t_tmp;
					*object =*iter;
					res =true;
				}
//			}
		}

		#ifdef _OPTIMIZE_collideRectToCircles
		if(V->x<0 || V->y>0)
		#endif
		if(ph->rayToCircle(cposition, radius_ph, &pLoHi, V, &t_tmp)){

//			if(t_tmp>0 && t_tmp<1){

				if(!res || t_tmp<*t_min){

					p_tmp =&pLoHi;
					*t_min =t_tmp;
					*object =*iter;
					res =true;
				}
//			}
		}

		#ifdef _OPTIMIZE_collideRectToCircles
		if(V->x>0 || V->y>0)
		#endif
		if(ph->rayToCircle(cposition, radius_ph, &pHiHi, V, &t_tmp)){
			
//			if(t_tmp>0 && t_tmp<1){

				if(!res || t_tmp<*t_min){

					p_tmp =&pHiHi;
					*t_min =t_tmp;
					*object =*iter;
					res =true;
				}
//			}
		}
		// it is still possible that circle penetrates a side of the 'rect'
		Point2 Vv =-*V;	//? use global
		Rect rct =*rect;
		addVectToRect(&rct, position);
		if(ph->circleVToRect(radius_ph, cposition, &rct, &Vv, n, &t_tmp)){
//			if(t_tmp>0 && t_tmp<=1){

				if(!res || t_tmp<*t_min){

					p_tmp =NULL;
					*t_min =t_tmp;
					*object =*iter;
					res =true;
				}
//			}
		}
	}

	if(res){

		if(!p_tmp){				// circle penetrated the rectangle
			n->x =-n->x;
			n->y =-n->y;
		}
		else
			*n =*p_tmp+(*V*(*t_min))-*((*object)->position);
	}

	return res;
}

// collide rectangle 'rect', moving by 'V', to level's vertical boundaries
// return 'true' if there is a collision, n-normal to the point of collision 't_min' -its t
//? no need for this function
bool Game::collideRectToLevelVert(Level* level, Rect* rect, Point2* position, Point2* v, float* t_tmp, Point2* n){

	assert(rect);
	assert(position);
	assert(level);
	assert(v);

	Point2 o;
	Physics* ph =Physics::Instance();

	o.y =0;
	if(v->x<0){

		o.x =rect->xLo + position->x;
		if(ph->rayToVertLine(level->rect->xLo, -1000000, 1000000, &o, v, t_tmp)){		
//			if(*t_tmp>0 && *t_tmp<1){
				n->x =1;
				n->y =0;
				return true;
//			}
		}
	}

	if(v->x>0){
		o.x =rect->xHi + position->x;
		if(ph->rayToVertLine(level->rect->xHi, -1000000, 1000000, &o, v, t_tmp)){
		
//			if(*t_tmp>0 && *t_tmp<1){
				n->x =-1;
				n->y =0;
				return true;
//			}
		}
	}

	return false;
}

// collide rectangle 'rect', moving by 'V', to all the slopes in the 'level'
// return 'true' if there is a collision, n-normal to the point of collision 't_min' -its t
bool Game::collideRectToSlopes(Level* level, Rect* rect, Point2* position, Point2* v, Point2* n, float* t_min, Object** object){

	assert(rect);
	assert(position);
	assert(level);
	assert(v);

	Physics* ph =Physics::Instance();
	
	float t_tmp;
	list<Slope*>::iterator iter;
	Point2 s1, s2, normal;

	bool res =false;

	Rect rectT =*rect;
	addVectToRect(&rectT, position);

	#ifdef _OPTIMIZE_collideRectToSlopes
	Rect rectS;
	Rect rectD =rectT;
	if(v->x>0)
		rectD.xHi +=v->x;
	else
		rectD.xLo +=v->x;
	if(v->y>0)
		rectD.yHi +=v->y;
	else
		rectD.yLo +=v->y;
	#endif

	for(iter = level->slopes.begin(); iter != level->slopes.end(); iter++)
	{
		// set static points - endpoints of the slope
		s1 =*((*iter)->pLo_ph) + *((*iter)->position);
		s2 =*((*iter)->pHi_ph) + *((*iter)->position);

		#ifdef _OPTIMIZE_collideRectToSlopes
		// find object's current box
		if(s1.x>s2.x){
			rectS.xHi =s1.x;
			rectS.xLo =s2.x;
		}
		else {
			rectS.xHi =s2.x;
			rectS.xLo =s1.x;
		}

		if(s1.y>s2.y){
			rectS.yHi =s1.y;
			rectS.yLo =s2.y;
		}
		else {
			rectS.yHi =s2.y;
			rectS.yLo =s1.y;
		}

		if(!ph->collide_Rect_Rect_S(&rectS, &rectD)){
			continue;
		}
		#endif

		if(ph->rectToSegment(&rectT, &s1, &s2, v, &normal, &t_tmp)){

			if(!res || t_tmp <*t_min){

				*t_min =t_tmp;
				*n =normal;
				res =true;
				*object =*iter;
			}
		}
	}

	return res;
}

// collide rectangle 'rect', moving by 'V', to all the floors in the 'level'
// return 'true' if there is a collision, n-normal to the point of collision 't_min' -its t
// optimise: floor->frame->body
bool Game::collideRectToFloors(Level* level, Rect* rect, Point2* position, Point2* v, float* t_min, Object** object){

	assert(rect);
	assert(position);
	assert(level);
	assert(v);

	// we cannot penetrate any floor by moving otherwise than downwards
	if(v->y>=0) return false;

	Physics* ph =Physics::Instance();
	float t_tmp, y, xLo, xHi;
	Point2 o, v_tmp;
	int i;
	Platform* floor;
	bool res =false;

	#ifdef _OPTIMIZE_collideRectToFloors
	Rect rectD =*rect;
	addVectToRect(&rectD, position);
	if(v->x>0)
		rectD.xHi +=v->x;
	else
		rectD.xLo +=v->x;
	if(v->y>0)
		rectD.yHi +=v->y;
	else
		rectD.yLo +=v->y;
	#endif

	for(i =0; i <level->floors_num; i++)
	{
		floor =level->floors[i];

		y =floor->frame->body->yHi +floor->position->y;
		xLo =floor->frame->body->xLo +floor->position->x;
		xHi =floor->frame->body->xHi +floor->position->x;
		#ifdef _OPTIMIZE_collideRectToFloors
		if(y<rectD.yLo) continue;
		if(y>rectD.yHi) continue;
		if( xHi < rectD.xLo) continue;
		if( xLo > rectD.xHi) continue;
		#endif

		o.y =rect->yLo +position->y;
		o.x =rect->xLo +position->x;
		// we only need to check rectangle's bottom
		// 2 rays from the rect's bottom edge should be fired to the floor's top
		if(ph->rayToHorLine(y, xLo, xHi, &o, v, &t_tmp)){

			if(!res || t_tmp <*t_min){
				*t_min =t_tmp;
				*object =floor;
				res =true;
			}
		}
		o.x =rect->xHi +position->x;
		if(ph->rayToHorLine(y, xLo, xHi, &o, v, &t_tmp)){

			if(!res || t_tmp <*t_min){
				*t_min =t_tmp;
				*object =floor;
				res =true;
			}
		}

		// it is still possible that the floor penetrates the rect
		// 2 rays from floor's endpoints shoold be fired to the rect's bottom edge
		v_tmp =-*v;
		o.y =y;
		o.x =xLo;
		y =rect->yLo +position->y;
		xLo =rect->xLo +position->x;
//		xHi =rect->xHi +position->x;
		if(ph->rayToHorLine(y, xLo, rect->xHi +position->x, &o, &v_tmp, &t_tmp)){

			if(!res || t_tmp <*t_min){
				*t_min =t_tmp;
				*object =level->floors[i];
				res =true;
			}
		}
		o.x =xHi;
		if(ph->rayToHorLine(rect->yLo, rect->xLo, rect->xHi, &o, &v_tmp, &t_tmp)){

			if(!res || t_tmp <*t_min){
				*t_min =t_tmp;
				*object =floor;
				res =true;
			}
		}
	}

	return res;
}

// collide rectangle 'rect', moving by 'V', to all the platforms in the 'level'
// return 'true' if there is a collision, n-normal to the point of collision 't_min' -its t
bool Game::collideRectToPlatforms(Level* level, Rect* rect, Point2* position, Point2* v, float* t_min, Point2* n, Object** object){

	assert(rect);
	assert(position);
	assert(level);
	assert(v);

	Physics* ph =Physics::Instance();
	int i;
	float t_tmp;
	Rect boxD;
	Rect boxS;
	Point2 v_tmp, normal;
	int platforms_num;
	Platform* platform;
	bool res=false;

	// set D-box to player's new posittion
	boxD =*rect;
	addVectToRect(&boxD, position);

	#ifdef _OPTIMIZE_collideRectToPlatforms
	Rect boxT;
	boxT =boxD;
	if(v->x>0)
		boxT.xHi +=v->x;
	else
		boxT.xLo +=v->x;
	if(v->y>0)
		boxT.yHi +=v->y;
	else
		boxT.yLo +=v->y;
	#endif

	platforms_num =level->platforms_num;
	// for each object check if D-box overlap S-box
	for(i=0; i <platforms_num; i++)
	{
		platform =level->platforms[i];

		// find platform's current box
		boxS =*(platform->frame->body);
		addVectToRect(&boxS, platform->position);

		#ifdef _OPTIMIZE_collideRectToPlatforms
		if(!ph->collide_Rect_Rect_S(&boxS, &boxT)){
			continue;
		}
		#endif

		if(ph->rectToRect(&boxS, &boxD, v, &normal, &t_tmp)){

			if(!res || t_tmp<*t_min){
				*t_min =t_tmp;
				*n =normal;
				*object =platform;
				res =true;
			}
		}

		// check if the another rectangle penetrates the 'rect'
		v_tmp =-*v;
		if(ph->rectToRect(&boxD, &boxS, &v_tmp, &normal, &t_tmp)){

			if(!res || t_tmp<*t_min){
				*t_min =t_tmp;
				*n =normal;
				*object =platform;
				res =true;
			}
		}
	}

	return res;
}

// collide circle 'circle', moving by 'V', to all the platforms in the 'level'
// return 'true' if there is a collision, n-normal to the point of collision 't_min' -its t
bool Game::collideCircleToPlatforms(Level* level, float radius, Point2* position, Point2* v, float* t_min, Point2* n, Object** object){
/*
	assert(position);
	assert(level);
	assert(v);

	Physics* ph =Physics::Instance();
	int i;
	float t_tmp;
	Rect boxD;
	Rect boxS;
	Point2 v_tmp, normal;
	bool res=false;

	// for each object check if D-box overlap S-box
	for(i =0; i<level->platforms_num; i++)
	{
		// find object's current box
		boxS =*(level->platforms[i]->frame->body);
		addVectToRect(&boxS, level->platforms[i]->position);
		
		if(ph->circleVToRect(radius, position, &boxS, v, &normal, &t_tmp)){

			if(!res || t_tmp<*t_min){

				*t_min =t_tmp;
				*n =normal;
				*object =level->platforms[i];
			}

			res =true;
		}

//		v_tmp =-*v;
//		if(rectToRect(&boxD, &boxS, &v_tmp, &normal, &t_tmp)){
//
//			if(!res || t_tmp<*t_min){
//
//				*t_min =t_tmp;
//				*n =normal;
//			}
//
//			res =true;
//		}
	}

	return res;
*/
	return false;
}

// return true if rectangle 'rect' stands on any floor in the 'level'
bool Game::standsRectAtFloors(Level* level, Rect* rect, Point2* position, Object** object){

	assert(level);
	assert(rect);
	assert(position);

	float floor_y, player_y, floor_xHi, floor_xLo, player_xHi, player_xLo;
	Platform* floor;
	int i, floors_num;

	player_xHi =rect->xHi + position->x;
	player_xLo =rect->xLo + position->x;
	player_y =rect->yLo + position->y;

	floors_num =level->floors_num;
	for(i =0; i < floors_num; i++)
	{
		floor =level->floors[i];

		// here we perform test like optimization technique in sollideRectToFloors
		floor_y =floor->frame->body->yHi + floor->position->y;
		if(floor_y > player_y) continue;
		if(floor_y < player_y - STAND_TEST) continue;
		floor_xHi =floor->frame->body->xHi + floor->position->x;
		if(floor_xHi < player_xLo) continue;
		floor_xLo =floor->frame->body->xLo + floor->position->x;
		if(floor_xLo > player_xHi) continue;
//		//? can be optimized like this:
//		if((floor->frame->body->xHi + floor->position->x) < player_xLo) continue;
//		if((floor->frame->body->xLo + floor->position->x) > player_xHi) continue;

		*object =floor;
		return true;
	}

	return false;
}

// return true if rectangle 'rect' stands on any platform in the 'level'
// very much like 'standsRectAtFloors'
// unify //?
bool Game::standsRectAtPlatforms(Level* level, Rect* rect, Point2* position, Object** object){

	assert(level);
	assert(rect);
	assert(position);

	float platform_y, rect_y, platform_xHi, platform_xLo, rect_xHi, rect_xLo;
	Platform* platform;
	int i, platforms_num;

	rect_xHi =rect->xHi + position->x;
	rect_xLo =rect->xLo + position->x;
	rect_y =rect->yLo + position->y;

	platforms_num =level->platforms_num;
	for(i =0; i < platforms_num; i++)
	{
		platform =level->platforms[i];

		// here we perform test like optimization technique in sollideRectToplatforms
		platform_y =platform->frame->body->yHi + platform->position->y;
		if(platform_y > rect_y) continue;
		if(platform_y < rect_y - STAND_TEST) continue;
		platform_xHi =platform->frame->body->xHi + platform->position->x;
		if(platform_xHi < rect_xLo) continue;
		platform_xLo =platform->frame->body->xLo + platform->position->x;
		if(platform_xLo > rect_xHi) continue;
//		//? can be optimized like this:
//		if((platform->frame->body->xHi + platform->position->x) < player_xLo) continue;
//		if((platform->frame->body->xLo + platform->position->x) > player_xHi) continue;

		*object =platform;
		return true;
	}

	return false;
}

/*
bool Game::standsRectAtSlopes(Level* level, Rect* rect, Point2* position, Object** object){

	assert(rect);
	assert(position);
	assert(level);
//	assert(v);

	Physics* ph =Physics::Instance();
	
//	float t_tmp;
	list<Slope*>::iterator iter;
	Point2 s1, s2, normal, d1, d2, d3, d4, p_tmp;

	Rect rectD =*rect;
	addVectToRect(&rectD, position);

	Rect rectS;
//	Rect rectD =rectT;
//	if(v->x>0)
//		rectD.xHi +=v->x;
//	else
//		rectD.xLo +=v->x;
//	if(v->y>0)
//		rectD.yHi +=v->y;
//	else
//		rectD.yLo +=v->y;
	rectD.yLo -=STAND_TEST;

	d1.x =rectD.xHi;
	d1.y =rectD.yHi;
	d2.x =rectD.xHi;
	d2.y =rectD.yLo;

	d3.x =rectD.xLo;
	d3.y =rectD.yHi;
	d4.x =rectD.xLo;
	d4.y =rectD.yLo;

	for(iter = level->slopes.begin(); iter != level->slopes.end(); iter++)
	{
		// set static points - endpoints of the slope
		s1 =*((*iter)->pLo_ph) + *((*iter)->position);
		s2 =*((*iter)->pHi_ph) + *((*iter)->position);

		// find object's current box
		if(s1.x>s2.x){
			rectS.xHi =s1.x;
			rectS.xLo =s2.x;
		}
		else {
			rectS.xHi =s2.x;
			rectS.xLo =s1.x;
		}

		if(s1.y>s2.y){
			rectS.yHi =s1.y;
			rectS.yLo =s2.y;
		}
		else {
			rectS.yHi =s2.y;
			rectS.yLo =s1.y;
		}

		if(!ph->collide_Rect_Rect_S(&rectS, &rectD)){
			continue;
		}

		if(ph->intersectSegments(&s1, &s2, &d1, &d2, &p_tmp))
			return true;
		if(ph->intersectSegments(&s1, &s2, &d3, &d4, &p_tmp))
			return true;

		if(ph->pointInRect(s1.x, s1.y, &rectD))
			return true;
		if(ph->pointInRect(s2.x, s2.y, &rectD))
			return true;
	}

	return false;
}
*/

// return true if 'circle' stands on any platform in the 'level'
bool Game::standsCircleAtPlatforms(Level* level, float radius, Point2* position, Object** object){
/*
	assert(level);
	assert(position);

	int i;
	Rect boxD, boxS;
	Point2 v, normal;
	float t;
	Physics* ph =Physics::Instance();

	v.x =0;// =*(circle->origin);
	v.y =-STAND_TEST;

	// for each object check if D-box overlap S-box
	for(i =0; i<level->platforms_num; i++)
	{
		// find object's current box
		boxS =*(level->platforms[i]->frame->body);
		addVectToRect(&boxS, level->platforms[i]->position);

		if(ph->circleVToRect(radius, position, &boxS, &v, &normal, &t))
			return true;
	}
*/
	return false;
}

// return true if 'rect' close to the level geometry, false otherwise
// out: n - normal to the surface
bool Game::standsRectAtLevel(Level* level, Rect* rect, Point2* position, Point2* n, Object** object){

	// fust placeholders - we do not use thir values
	Point2 p_tmp;
	float t;

	// {o} - we remember which kind of geometry the rect satanded upon in the previous call, and try this geometry first
	// work best when there is only one rect
	#ifdef _OPTIMIZE_standsRectAtLevel
	switch(_stand_prediction){
	case PLATFORMS:

		if(standsRectAtPlatforms(level, rect, position, object)){

			n->x =0;
			n->y =1;
			_stand_prediction =PLATFORMS;
			return true;
		}
		break;
	case FLOORS:
		if(standsRectAtFloors(level, rect, position, object)){

			n->x =0;
			n->y =1;
			_stand_prediction =FLOORS;
			return true;
		}
		break;
	case SLOPES:
		if(collideRectToSlopes(level, rect, position, &V_STAND_TEST, n, &t, object)){
			_stand_prediction =SLOPES;
			return true;
		}
		break;
	case CIRCLES:
		if(collideRectToCircles(level, rect, position, &V_STAND_TEST, n, &t, object)){
			_stand_prediction =CIRCLES;
			return true;
		}
		break;
	}
	if(_stand_prediction !=PLATFORMS)
	#endif

	if(standsRectAtPlatforms(level, rect, position, object)){

		n->x =0;
		n->y =1;
		_stand_prediction =PLATFORMS;
		return true;
	}
	#ifdef _OPTIMIZE_standsRectAtLevel
	if(_stand_prediction !=FLOORS)
	#endif
	if(standsRectAtFloors(level, rect, position, object)){

		n->x =0;
		n->y =1;
		_stand_prediction =FLOORS;
		return true;
	}
	#ifdef _OPTIMIZE_standsRectAtLevel
	if(_stand_prediction !=SLOPES)
	#endif
//	if(standsRectAtSlopes(level, rect, position, object))	//?
	if(collideRectToSlopes(level, rect, position, &V_STAND_TEST, n, &t, object)){
		_stand_prediction =SLOPES;
		return true;
	}
	#ifdef _OPTIMIZE_standsRectAtLevel
	if(_stand_prediction !=CIRCLES)
	#endif
	if(collideRectToCircles(level, rect, position, &V_STAND_TEST, n, &t, object)){
		_stand_prediction =CIRCLES;
		return true;
	}

	return false;
}

// collide rectangle 'rect', moving by 'V', to the level's geometry
// return 'true' if there is a collision, n-normal to the point of collision 't_min' -its t
bool Game::collideRectToLevel(Level* level, Rect* rect, Point2* position, Point2* v, float* t_min, Point2* n, unsigned int flag, Object** object){

/*
	Point2 v_old =*v;
	float new_mag =v->Mag() +D_TOUCH;
	v->Normalize();
	*v *=new_mag;
*/
	Point2 normal;
	float t_tmp;
	bool res;

	res =false;
	// here we have to collide to all the geometry to find the smallest 't'
	if(flag & PLATFORMS){

		if(collideRectToPlatforms(level, rect, position, v, &t_tmp, &normal, object)){

//			if(!res || t_tmp < *t_min){	// fist
				*t_min =t_tmp;
				*n =normal;
				res =true;
//			}
		}
	}

	if(flag & FLOORS){

		if(collideRectToFloors(level, rect, position, v, &t_tmp, object)){
			
			if(!res || t_tmp < *t_min){
				*t_min =t_tmp;
				n->x =0;
				n->y =1;
				res =true;
			}
		}
	}

	if(flag & SLOPES){

		if(collideRectToSlopes(level, rect, position, v, &normal, &t_tmp, object)){

			if(!res || t_tmp < *t_min){
				*t_min =t_tmp;
				*n =normal;
				res =true;
			}
		}
	}

	if(flag & CIRCLES){

		if(collideRectToCircles(level, rect, position, v, &normal, &t_tmp, object)){

			if(!res || t_tmp < *t_min){
				*t_min =t_tmp;
				*n =normal;
				res =true;
			}
		}
	}

	if(flag & LEVEL){

		if(collideRectToLevelVert(level, rect, position, v, &t_tmp, &normal)){
	
			if(!res || t_tmp < *t_min){
				*t_min =t_tmp;
				*n =normal;
				res =true;
			}
		}
	}

	float mag =v->Mag();
	float tmp =*t_min*mag;
	if (tmp >= 0 && tmp < TTT) {
		TTT = tmp;
	}

	// tn / (t * m - d) = t / (t * m)
	if(res){
/*
		float tmp =v->Mag()*(*t_min);
		if(tmp >D_TOUCH){
			
			*t_min =*t_min*(tmp-D_TOUCH)/tmp;
		}
		else 
			*t_min =0;
*/
/*
		//float mag =v->Mag();
		//float tmp =*t_min*mag;
		if(tmp >D_TOUCH){
			
			//*t_min =(tmp - D_TOUCH)/mag;
			*t_min -= D_TOUCH/mag;
		}
	 	else 
			*t_min =0;
			*/
	}

//	*v =v_old;



	return res;
}

// return true if 'circle' close to the level geometry, false otherwise
// out: n - normal to the surface
bool Game::standsCircleAtLevel(Level* level, float radius, Point2* position, Point2* n, Object** object){

	/*
//	Point2 p_tmp;
//	float t;

//	if(collideToSlopes(level, rect, position, &V_STAND_TEST, n, &t))
//		return true;

//	if(collideToCircles(level, rect, position, &V_STAND_TEST, n, &t)){
//		return true;
//	}

//	//? //o run these first
	if(standsCircleAtPlatforms(level, radius, position, object)){

		n->x =0;
		n->y =1;
		return true;
	}

//	if(standsAtFloors(level, rect, position)){

//		n->x =0;
//		n->y =1;
//		return true;
//	}
*/
	return false;
}

// collide rectangle 'rect', moving by 'V', to the level's geometry
// return 'true' if there is a collision, n-normal to the point of collision 't_min' -its t
bool Game::collideCircleToLevel(Level* level, float radius, Point2* position, Point2* v, float* t_min, Point2* n, unsigned int flag, Object** object){

	/*
	Point2 normal;
	float t_tmp;
	bool res;

	res =false;

	if(flag & PLATFORMS){

		if(collideCircleToPlatforms(level, radius, position, v, &t_tmp, &normal, object)){

			if(!res || (t_tmp < *t_min)){
				*t_min =t_tmp;
				*n =normal;
			}

			res =true;
		}
	}

	if(res){
		float tmp =v->Mag()*(*t_min);
		if(tmp >=D_TOUCH){
			
			*t_min =*t_min*(tmp-D_TOUCH)/tmp;
		}
		else 
			*t_min =0;
	}

	return res;
	*/
	return false;
}

// update all the zombies in the 'level'
void Game::updateZombies(Level* level, Character* player, Camera* camera, float dt){

	Point2 p_tmp;
	list<Zomby*>::iterator iter;
	p_tmp =V_DOWN*level->gravity;
	Physics* ph =Physics::Instance();
	Zomby* zomby;

	for(iter = level->zombies.begin(); iter != level->zombies.end(); iter++)
	{
		zomby =*iter;
		// if the zomby is not active - skip it
		if(!zomby->active) continue;

		// update zombie's timer
		zomby->ai->cur_time +=dt;
		// if it is time for the zomby to die - deactivate him
		if(zomby->ai->cur_time >=zomby->ai->max_time){

			RECT_TMP =*(zomby->cur_animation->frames[zomby->cur_animation->cur_frame]->box);
			addVectToRect(&RECT_TMP, zomby->position);
			// deactivate him only if it does not overlap with the camera rect
			if(!ph->collide_Rect_Rect_S(camera->rect, &RECT_TMP)){
					zomby->active =false;
					continue;
			}
		}
		// if the zomby should think
		if(zomby->state==STATE_STILL || zomby->state==STATE_MOVE){

			if(!aiAttack(player, zomby))		// try to attack
				if(!aiFollowMe(player, zomby))	// if not - try to follow the player
					aiLine(zomby);				// if not - stroll
		}

		// update zomby's state
		zomby->update(level, &p_tmp, dt);		// gravity 1/1000ms
	}
}

// update all the birds in the 'level'
void Game::updateBirds(Level* level, Character* player, float dt){

	Point2 p_tmp;
	list<Bird*>::iterator iter;
	p_tmp =V_DOWN*level->gravity;
	Bird* bird;

	for(iter = level->birds.begin(); iter != level->birds.end(); iter++)
	{
		bird =*iter;
		// if the zomby is not active - skip it
		if(!bird->active) continue;

		// if the bird should think
		if(bird->state==STATE_STILL || bird->state==STATE_MOVE){
			aiLine(bird);						// stroll
		}

		bird->update(level, &p_tmp, dt);		// gravity 1/1000ms
	}
}

// update all the koloboks in the 'level'
void Game::updateKoloboks(Level* level, Character* player, float dt){

/*
	Point2 p_tmp;
	list<Kolobok*>::iterator iter;
	p_tmp =V_DOWN*level->gravity;

	for(iter = level->koloboks.begin(); iter != level->koloboks.end(); iter++)
	{
		(*iter)->update(level, &p_tmp, dt);
	}
*/
}

// collide point 'o' moving by 'd' to the 'level'
// return object it collided into, 'n' -normal to the poit of collision, 'p' -the point itself
void* Game::collidePointToLevel(Level* level, Point2* o, Point2* d, Point2* p, Point2* normal, unsigned int flag, unsigned int* type){

	int i;
	float t_min =1.0f, t_tmp;
	list<Zomby*>::iterator iter_zomby;
	list<Slope*>::iterator iter_slope;
	list<Circle*>::iterator iter_circle;
	list<Kolobok*>::iterator iter_kolobok;
	list<Bird*>::iterator iter_bird;
	Point2 p_tmp, p3, p4, normal_tmp;
	Rect rect;
	void* ret =NULL;
	Point2 n;
	Platform* platform;
	Zomby* zomby;
	Bird* bird;
	Slope* slope;
	Circle* circle;
	Kolobok* kolobok;
	float ang;

	Physics* ph =Physics::Instance();
	*type =NONE;

	if(flag && PLATFORMS)
	for(i =0; i<level->platforms_num; i++)
	{
		platform =level->platforms[i];
		rect =*(platform->frame->body);
		addVectToRect(&rect, platform->position);
		if(ph->rayToRect(&rect, o, d, &t_tmp, &n)){

			if(t_tmp<t_min){
				*type =PLATFORMS;
				ret =platform;
				t_min =t_tmp;
				*normal =n;
			}
		}
	}

	if(flag && ZOMBIES)
	for(iter_zomby = level->zombies.begin(); iter_zomby != level->zombies.end(); iter_zomby++)
	{
		zomby =*iter_zomby;
		if(!zomby->active) continue;
//		if((*iter_zomby)->state==STATE_ROT) continue;	//?
		rect =*(zomby->getBody());
		addVectToRect(&rect, zomby->position);
		if(ph->rayToRect(&rect, o, d, &t_tmp, &n)){

			if(t_tmp<t_min){
				*type =ZOMBIES;
				ret =zomby;
				t_min =t_tmp;
				*normal =n;
			}
		}
	}

	if(flag && BIRDS)
	for(iter_bird = level->birds.begin(); iter_bird != level->birds.end(); iter_bird++)
	{
		bird =*iter_bird;
		if(!bird->active) continue;
		rect =*(bird->getBody());
		addVectToRect(&rect, bird->position);
		if(ph->rayToRect(&rect, o, d, &t_tmp, &n)){

			if(t_tmp<t_min){
				*type =BIRDS;
				ret =bird;
				t_min =t_tmp;
				*normal =n;
			}
		}
	}

	if(flag && SLOPES)
	for(iter_slope = level->slopes.begin(); iter_slope != level->slopes.end(); iter_slope++)
	{
		slope =*iter_slope;
		p3 =*(slope->pLo_ph)  +*(slope->position);
		p4 =*(slope->pHi_ph)  +*(slope->position);
		if(ph->rayToSegment(&p3, &p4, o, d, &n, &t_tmp)){
		
			if(t_tmp<t_min){
				*type =SLOPES;
				ret =slope;
				t_min =t_tmp;
				ang =acos((n*-(*d)) / (n.Mag()*d->Mag()));
				if( ang>PI*0.5 )		// angle between the dirrection and the normal shold be less the 90
					n=-n;
				*normal =n;
			}
		}
	}

	if(flag && CIRCLES)
	for(iter_circle = level->circles.begin(); iter_circle != level->circles.end(); iter_circle++)
	{
		circle =*iter_circle;
		if(ph->rayToCircle(circle->position, circle->radius_ph, o, d, &t_tmp)){

			if(t_tmp<t_min){
				*type =CIRCLES;
				ret =circle;
				t_min =t_tmp;
				p_tmp =*o +*d*t_tmp;					// collision point
				*normal =p_tmp -*(circle->position);	// normal
			}
		}
	}

	if(flag && KOLOBOKS)
	for(iter_kolobok = level->koloboks.begin(); iter_kolobok != level->koloboks.end(); iter_kolobok++)
	{
		kolobok =*iter_kolobok;
		if(ph->rayToCircle(kolobok->position, kolobok->circle->radius_ph, o, d, &t_tmp)){

			if(t_tmp<t_min){
				*type =KOLOBOKS;
				ret =kolobok;
				t_min =t_tmp;
				p_tmp =*o +*d*t_tmp;					// collision point
				*normal =p_tmp -*(kolobok->position);	// normal
			}
		}
	}

	if(ret){

		*p =*o +(*d)*t_min;
	}

	return ret;
}

// check game logic - whatever it means
int Game::checkLogics(Level* level, Character* player){

	list<Platform*>::iterator iter_item;
	list<Zomby*>::iterator iter_zomby;
	list<Bird*>::iterator iter_bat;
	Rect player_rect;
	Rect r;
	float x,y;
	Physics* ph =Physics::Instance();
	Audio* audio =Audio::Instance();
	Zomby* zomby;

	player_rect =*(player->getBody());
	addVectToRect(&player_rect, player->position);

	// check if any new item is collected - mark it if so
	for(iter_item = level->items.begin(); iter_item != level->items.end(); iter_item++)
	{	
		r =*((*iter_item)->frame->body);
		addVectToRect(&r, (*iter_item)->position);
		if(ph->collide_Rect_Rect_S(&player_rect, &r)){
			(*iter_item)->dead =true;
		}		
	}

	// check if hit by bat
	for(iter_bat = level->birds.begin(); iter_bat != level->birds.end(); iter_bat++)
	{	
		r =*((*iter_bat)->getBody());
		addVectToRect(&r, (*iter_bat)->position);
		if(ph->collide_Rect_Rect_S(&player_rect, &r)){
			if(player->state!=STATE_DEAD){
//				player->setState(STATE_DEAD, 0);
				player->setDead(0);
				// play die sound
				audio->setSource(player->src_death->id, player->src_death->buffer, player->getCenterX(), player->position->y + player->head_level, 0, player->src_death->gain, player->src_death->loop);	//? create function
				audio->playSource(player->src_death->id);
			}
		}		
	}

	// check for the winning situation
	r =*(level->finish->frame->body);
	addVectToRect(&r, level->finish->position);
	//? can slip through
	if(ph->collide_Rect_Rect_S(&player_rect, &r)){
		// play winning sound
		audio->setSource(level->src_win->id, level->src_win->buffer, player->getCenterX(), player->position->y + player->head_level, 0, level->src_win->gain, level->src_win->loop);
		audio->playSource(level->src_win->id);
		return GAME_WON;
	}

	// if player has fallen below the 'deadline' - kill him
	if(player_rect.yLo < level->deadline){

		if(player->state!=STATE_DEAD){
//			player->setState(STATE_DEAD, 0);
			player->setDead(0);			
			// play die sound
			audio->setSource(player->src_death->id, player->src_death->buffer, player->getCenterX(), player->position->y + player->head_level, 0, player->src_death->gain, player->src_death->loop);
			audio->playSource(player->src_death->id);
		}
	}

	// if player has fallen far below the 'deadline' - GAME OVER
	if(player_rect.yLo < level->deadline - 200){	//? constant
		
		if(player->state==STATE_DEAD)
			return GAME_LOST;
	}
	
	// check for the enemy attack
	int frame_num;
	Point2** attack;
	for(iter_zomby = level->zombies.begin(); iter_zomby != level->zombies.end(); iter_zomby++){

		zomby =*iter_zomby;
		if(!zomby->active) continue;
		if(zomby->state==STATE_ATTACK){
			frame_num =zomby->cur_animation->cur_frame;
			if(zomby->cur_animation==zomby->ani_bite){

				attack =zomby->bite;
			}
			if(zomby->cur_animation==zomby->ani_kick){

				attack =zomby->kick;
			}
			if(attack[frame_num]){

				if(player->state!=STATE_DEAD){

					zomby->getCenter(&V_TMP);
					RECT_TMP =*(player->getBody());
					addVectToRect(&RECT_TMP, player->position);
					if(zomby->orientation->x>0)
						x =V_TMP.x +attack[frame_num]->x;
					else
						x =V_TMP.x -attack[frame_num]->x;
					y =attack[frame_num]->y +zomby->position->y;
					if(ph->pointInRect(x, y, &RECT_TMP)){

//						player->setState(STATE_DEAD, 0);
						player->setDead(0);
						// play die sound
						audio->setSource(player->src_death->id, player->src_death->buffer, player->getCenterX(), player->position->y + player->head_level, 0, player->src_death->gain, player->src_death->loop);
						audio->playSource(player->src_death->id);
					}
				}
			}
		}
	}

	return GAME_ON;
}

// process keys and make player's desisions
void Game::processKeys(Level* level, Character* player, mrKeyboard* kbd){

//	kbd->Update();
	player->moveXminus =false;
	player->moveXplus =false;
	player->moveYminus =false;
	player->moveYplus =false;
	player->attack =false;
	player->special =false;
	player->special2 =false;

	if (keys[VK_LEFT])
//	if(kbd->IsButtonDown(key_left))//DIK_LEFT))
	{
		player->moveXplus =true;
	}
	if (keys[VK_RIGHT])
//	if(kbd->IsButtonDown(key_right))//DIK_RIGHT))
	{
		player->moveXminus =true;
	}
	if (keys[VK_UP])
//	if(kbd->IsButtonDown(key_up))//DIK_UP))
	{
		player->moveYplus =true;
	}
	if (keys[VK_DOWN])
//	if(kbd->IsButtonDown(key_down))//DIK_DOWN))
	{
		player->moveYminus =true;
	}
	if (keys[VK_SHIFT])
//	if(kbd->IsButtonDown(key_special))//DIK_LSHIFT) || kbd->IsButtonDown(DIK_RSHIFT))
	{
		player->special =true;
	}

	if (keys[VK_TAB])
//	if(kbd->IsButtonDown(key_special))//DIK_LSHIFT) || kbd->IsButtonDown(DIK_RSHIFT))
	{
		player->special2 =true;
	}

	if (keys[VK_CONTROL])
//	if(kbd->IsButtonDown(key_attack))//DIK_LCONTROL) || kbd->IsButtonDown(DIK_RCONTROL))
	{
		player->attack =true;
	}
}

// move the clouds
// if the cloud left the level rect + camera's offset - put it at the start of the level
void Game::updateClouds(Level* level, Camera* camera, float dt){

	list<Cloud*>::iterator iter_cloud;
	float x;
	Cloud* cloud;

	for(iter_cloud = level->clouds.begin(); iter_cloud != level->clouds.end(); iter_cloud++)
	{
		cloud =*iter_cloud;
		x =(cloud->z -camera->frustum_near) *_tan_133;	// halfway to the camera's (right/left) end

		// if the coud is invisible and out of level rect - pu it at the level start		
		if(cloud->position->x +cloud->rect->xHi < level->rect->xLo -x)
			cloud->position->x =level->rect->xHi +x -cloud->rect->xLo;

		cloud->position->x -=cloud->speed*dt*0.1;
	}
}

// for each projectile - update its state and animation
void Game::updateProjectiles(Level* level, float dt){

	list<Projectile*>::iterator iter_projectile;
	Point2 dir, normal, p;
	float tmp;
	void* target;
	unsigned int type;
	Fx* fx;
	Projectile* projectile;
	Source* source;
	Bird* bird;
	Zomby* zomby;
	Kolobok* kolobok;
	Audio* audio =Audio::Instance();

	for(iter_projectile = level->projectiles.begin(); iter_projectile != level->projectiles.end(); )
	{
		projectile =*iter_projectile;
		tmp =projectile->speed*dt*0.1; // 100cm/1000ms
		dir =projectile->dir->Normalized()*tmp;
		
		// if there was a collision - remove the projectile and create explosion sfx
		target =collidePointToLevel(level, projectile->position, &dir, &p, &normal, PLATFORMS|ZOMBIES|SLOPES|CIRCLES|KOLOBOKS|BIRDS, &type);
		if(target){

			switch(type){
			case BIRDS:

				bird =static_cast<Bird*>(target);
//				bird->setState(STATE_DEAD, 0);
				bird->setDead(0);
				// throw the target by dirrection and a liitle upwards
				*(bird->velocity) =dir;
				bird->velocity->Normalize();
				bird->velocity->y +=1;
				*(bird->velocity) =*(bird->velocity)*2;	//?

				fx =new Fx(*FX_BANG);
				fx->position =new Point2;
				bird->getCenter(&V_TMP);
				*(fx->position) =p+(V_TMP -p)*0.5;
				fx->layer =projectile->layer;
				level->effects.push_back(fx);	

				// play hit sound
				source =createHitSource();
				assert(source);
				level->sources.push_back(source);
				audio->setSource(source->id, source->buffer, p.x, p.y, 0, source->gain, source->loop);
				audio->playSource(source->id);
			break;
			case ZOMBIES:

				zomby =static_cast<Zomby*>(target);
//				zomby->setState(STATE_DEAD, 0);
				zomby->setDead(0);
				// throw the target by dirrection and a liitle upwards
				*(zomby->velocity) =dir;
				zomby->velocity->Normalize();
				zomby->velocity->y +=1;
				*(zomby->velocity) =*(zomby->velocity)*2;	//?

				fx =new Fx(*FX_BANG);
				fx->position =new Point2;
				zomby->getCenter(&V_TMP);
				*(fx->position) =p+(V_TMP -p)*0.5;
				fx->layer =projectile->layer;
				level->effects.push_back(fx);
				scores +=100;				//? const

				// play hit sound
				source =createHitSource();
				assert(source);
				level->sources.push_back(source);
				audio->setSource(source->id, source->buffer, p.x, p.y, 0, source->gain, source->loop);
				audio->playSource(source->id);
			break;
			case KOLOBOKS:

				kolobok =static_cast<Kolobok*>(target);
//				kolobok->setState(STATE_DEAD, 0);
				kolobok->setDead(0);
				// throw the target by dirrection and a liitle upwards
				*(kolobok->velocity) =dir;
				kolobok->velocity->Normalize();
				kolobok->velocity->y +=1;
				*(kolobok->velocity) =*(kolobok->velocity)*2;	//?
			break;
			case SLOPES:
			case CIRCLES:
			case PLATFORMS:
				// play ricochet sound
				source =createRikSource();
				assert(source);
				level->sources.push_back(source);
				audio->setSource(source->id, source->buffer, p.x, p.y, 0, source->gain, source->loop);
				audio->playSource(source->id);

				fx =new Fx(*FX_RIK);
				fx->quad =fx->getQuad(&p, &normal);
				fx->layer =projectile->layer;
				level->effects.push_back(fx);
				break;
			}

			projectile->dead =true;
		}
		else{

			*(projectile->position) +=dir;
			projectile->cur +=tmp;
		}

		// if maximum distance was reached - remove the projectile
		if(projectile->cur >=projectile->max){

			projectile->dead =true;
		}
	
		iter_projectile++;
	}
}

// select randomly raspawn point and respawn a single zomby
void Game::createZombies(Level* level){

	int rnd, rnd2;
	list<Zomby*>::iterator iter_zomby;
	Zomby* zomby;

	if(level->respawns_num==0) return;

	for(iter_zomby = level->zombies.begin(); iter_zomby != level->zombies.end(); iter_zomby++)
	{
		zomby =*iter_zomby;
		if(zomby->active) continue;		

		// select respawn point
		rnd =rand()%level->respawns_num;
		// respawn the zomby
		*(zomby->ai) =*(level->respawns[rnd]->ai);
		rnd2 =rand()%20;		//? constatnt?
		zomby->ai->attack_proximity -=zomby->ai->attack_proximity*(static_cast<float>(rnd2)*0.01f);
		*(zomby->position) =*(level->respawns[rnd]->position);

//		zomby->setState(STATE_BORN, 0);
		zomby->setJump(0);
		zomby->orientation->y =0;
		zomby->orientation->x =-1;

		zomby->layer =level->respawns[rnd]->layer;
		zomby->ai->cur_time =0;

		zomby->velocity->x =0;
		zomby->velocity->y =5;

		zomby->moveXminus =false;
		zomby->moveXplus =false;
		zomby->moveYminus =false;
		zomby->moveYplus =false;
		zomby->active =true;
		break;
	}
}

int Game::runGameLogic(Level* level, Character* player, Camera* cam, float dt){

	int logic;
	int passed_frames;
	div_t div_tmp;
	static float rem =0;
	Point2 v_tmp;
	static int create_zomby_time =0;

	list<Zomby*>::iterator iter_zomby;
	list<Kolobok*>::iterator iter_kolobok;
	list<Fx*>::iterator iter_fx;
	list<Platform*>::iterator iter_item;
	list<Projectile*>::iterator iter_projectile;
	list<Source*>::iterator iter_source;
	list<Bird*>::iterator iter_bird;
	Fx* fx;
	Projectile* projectile;
	Zomby* zomby;
	Bird* bird;
	Kolobok* kolobok;
	Platform* item;
	Source* source;
	Audio* audio =Audio::Instance();

	rem +=dt;
//	int time_tmp =timeGetTime();
	LARGE_INTEGER lctr1;
	QueryPerformanceCounter(&lctr1);
	int ctr =0;
	while(rem>LOGIC_CYCLE_TIME)
	{
		v_tmp =V_DOWN*level->gravity;
		player->update(level, &v_tmp, LOGIC_CYCLE_TIME);
		updateZombies(level, player, cam, LOGIC_CYCLE_TIME);
		updateBirds(level, player, LOGIC_CYCLE_TIME);
		updateKoloboks(level, player, LOGIC_CYCLE_TIME);
		updateProjectiles(level, LOGIC_CYCLE_TIME);
		updateClouds(level, cam, LOGIC_CYCLE_TIME);
		
		create_zomby_time +=LOGIC_CYCLE_TIME;
		if(create_zomby_time>1000){		//? constant
			createZombies(level);
			create_zomby_time -=1000;
		}

		logic =checkLogics(level, player);
		switch(logic){
		
		// if the game is over - do not update the camera or move the listener
		case GAME_WON:
		case GAME_LOST:
			return logic;
		}

		// delete unneeded objects ---------------------------------------------------
		// fx
		Animation* animation;
		int frame_duration, passed_time;
		for(iter_fx = level->effects.begin(); iter_fx != level->effects.end(); )
		{
			fx =*iter_fx;
			animation =fx->animation;
			animation->begin_time +=LOGIC_CYCLE_TIME;
			passed_time =animation->begin_time;
			frame_duration =1000.0f/animation->fps;
			// is animation is not recurrent AND it (animation) has ended - remove the effect
			if(!fx->repeat && passed_time>=animation->nFrames*frame_duration){
				iter_fx = level->effects.erase(iter_fx);
				delete fx;
				continue;
			}

			passed_frames =passed_time/frame_duration;
			div_tmp =div(passed_frames, animation->nFrames);
			animation->cur_frame =div_tmp.rem;

			iter_fx++;
		}

		// projectiles - if any is dead - romove it
		for(iter_projectile = level->projectiles.begin(); iter_projectile != level->projectiles.end(); )
		{
			projectile =*iter_projectile;
			if(projectile->dead){
				iter_projectile =level->projectiles.erase(iter_projectile);
				delete projectile;
				continue;
			}

			iter_projectile++;
		}

		// if any zomby has fallen below the 'deadline' - deactivate him
		for(iter_zomby = level->zombies.begin(); iter_zomby != level->zombies.end(); iter_zomby++)
		{
			zomby =*iter_zomby;
			if(!zomby->active)
				continue;
			
			if(zomby->get_pic_yHi() <level->deadline)
				zomby->active =false;
		}

		// if any bird has fallen below the 'deadline' - deactivate it
		for(iter_bird = level->birds.begin(); iter_bird != level->birds.end(); iter_bird++)
		{
			bird =*iter_bird;
			if(!bird->active)
				continue;

			if(bird->get_pic_yHi()<level->deadline) //? not deadline but out of screen
				bird->active =false;
		}

		// if any kolobok has fallen below the 'deadline' - remove him
		for(iter_kolobok = level->koloboks.begin(); iter_kolobok != level->koloboks.end();)
		{
			kolobok =*iter_kolobok;
			if(kolobok->get_pic_yHi()< level->deadline){	//? not deadline but out of screen
				iter_kolobok =level->koloboks.erase(iter_kolobok);
				delete kolobok;
				continue;
			}

			iter_kolobok++;
		}

		// items
		for(iter_item = level->items.begin(); iter_item != level->items.end();)
		{
			item =*iter_item;
			if(item->dead){
				iter_item =level->items.erase(iter_item);
				delete item;
				continue;
			}			

			iter_item++;
		}

		// sources
		for(iter_source = level->sources.begin(); iter_source !=level->sources.end();)
		{
			source =*iter_source;
			if(!source->loop && !audio->isPlaying(source->id)){
				iter_source =level->sources.erase(iter_source);
				delete source;
				continue;
			}			

			iter_source++;
		}
		// -----------------------------------------------------------------------------
		rem -=LOGIC_CYCLE_TIME;
		ctr++;
	}
	LARGE_INTEGER lctr2;
	QueryPerformanceCounter(&lctr2);
//	LARGE_INTEGER lctr =lctr2-lctr1;
	float cycle =static_cast<float>(lctr2.QuadPart -lctr1.QuadPart)/static_cast<float>(ctr);
	cycle_time =static_cast<int>(cycle);

/*
	if(keys[' ']){
		keys[' '] =false;
		updateCharacter(cur_level, player, 33);
		updateZombies(cur_level, 33);
	}
*/

	// update listener
	Rect* rect =player->getBody();
	audio->SetListener(player->getCenterX(), player->position->y + player->head_level, 0, 0);
	// update local sounds
	if(player->state==STATE_DEAD){
		audio->moveTo(player->src_death->id, player->getCenterX(), player->position->y + player->head_level, 0);
	}
	audio->moveTo(level->src_win->id, player->getCenterX(), player->position->y + player->head_level, 0);	//?

	// update camera
	if( (level->rect->xHi < player->position->x +cam->width/2) || (level->rect->xLo > player->position->x -cam->width/2) ){


	}
	else{
		cam->rect->xLo =player->position->x -cam->width/2;
		cam->rect->xHi =cam->rect->xLo +cam->width;

		cam->eye->x =player->position->x;
	}

	// update camera
	if( (level->rect->yHi < player->position->y +cam->height/2) || (level->rect->yLo > player->position->y -cam->height/2) ){


	}
	else{
		cam->rect->yLo =player->position->y -cam->height/2;
		cam->rect->yHi =cam->rect->yLo +cam->height;

		cam->eye->y =player->position->y;
	}

	Renderer* renderer =Renderer::Instance();
	renderer->setCamera(cam);

	return GAME_ON;
}
